package besta.moon.sql.expression.function.time;

import besta.moon.sql.Expression;
import besta.moon.sql.datatype.DateTime;
import besta.moon.sql.datatype.MutableNumeric;
import besta.moon.sql.expression.function.ExpressionFunction;
import besta.moon.sql.parser.SQLTokenizer;

public class FunctionTimestampAdd extends ExpressionFunction {

    final private int interval;

    public FunctionTimestampAdd(int intervalType, Expression p1, Expression p2) {
        interval = FunctionTimestampDiff.mapIntervalType(intervalType);
        setParams(new Expression[]{p1, p2});
    }

    @Override
    public int getFunction() {
        return SQLTokenizer.TIMESTAMPADD;
    }

    @Override
    public boolean isNull() throws Exception {
        return param1.isNull() || param2.isNull();
    }

    @Override
    public boolean getBoolean() throws Exception {
        return getLong() != 0;
    }

    @Override
    public int getInt() throws Exception {
        return (int) getLong();
    }

    @Override
    public long getLong() throws Exception {
        if (isNull()) {
            return 0;
        }
        switch (interval) {
            case SQLTokenizer.SQL_TSI_FRAC_SECOND -> {
                return param2.getLong() + param1.getLong();
            }
            case SQLTokenizer.SQL_TSI_SECOND -> {
                return param2.getLong() + param1.getLong() * 1000;
            }
            case SQLTokenizer.SQL_TSI_MINUTE -> {
                return param2.getLong() + param1.getLong() * 60000;
            }
            case SQLTokenizer.SQL_TSI_HOUR -> {
                return param2.getLong() + param1.getLong() * 3600000;
            }
            case SQLTokenizer.SQL_TSI_DAY -> {
                return param2.getLong() + param1.getLong() * 86400000;
            }
            case SQLTokenizer.SQL_TSI_WEEK -> {
                return param2.getLong() + param1.getLong() * 604800000;
            }
            case SQLTokenizer.SQL_TSI_MONTH -> {
                DateTime.Details details2 = new DateTime.Details(param2.getLong());
                details2.month += param1.getLong();
                return DateTime.calcMillis(details2);
            }
            case SQLTokenizer.SQL_TSI_QUARTER -> {
                DateTime.Details details2 = new DateTime.Details(param2.getLong());
                details2.month += param1.getLong() * 3;
                return DateTime.calcMillis(details2);
            }
            case SQLTokenizer.SQL_TSI_YEAR -> {
                DateTime.Details details2 = new DateTime.Details(param2.getLong());
                details2.year += param1.getLong();
                return DateTime.calcMillis(details2);
            }
            default -> throw new Error();
        }

    }

    @Override
    public float getFloat() throws Exception {
        return getLong();
    }

    @Override
    public double getDouble() throws Exception {
        return getLong();
    }

    @Override
    public long getMoney() throws Exception {
        return getLong() * 10000;
    }

    @Override
    public MutableNumeric getNumeric() throws Exception {
        if (isNull()) {
            return null;
        }
        return new MutableNumeric(getLong());
    }

    @Override
    public Object getObject() throws Exception {
        if (isNull()) {
            return null;
        }
        return new DateTime(getLong(), SQLTokenizer.TIMESTAMP);
    }

    @Override
    public String getString() throws Exception {
        if (isNull()) {
            return null;
        }
        return new DateTime(getLong(), SQLTokenizer.TIMESTAMP).toString();
    }

    @Override
    public int getDataType() {
        return SQLTokenizer.TIMESTAMP;
    }

}
